package com.gitee.yongzhuzl.commonutil.util.http;

import com.gitee.yongzhuzl.commonutil.util.empty.EmptyUtil;
import org.apache.hc.client5.http.classic.methods.*;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.*;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * description: HttpClient工具类，客户端用于调用服务端的服务
 * @author 朱正磊
 * @date 2017-07-03 15:25:50
 */
public class HttpClientTool {

    private static final Logger log = LoggerFactory.getLogger(HttpClientTool.class);

    /**
     * description: 发送http get请求
     * @author 朱正磊
     * @date 2025-09-02 15:38:09
     */
    public static HttpResponse httpGet(String url, Map<String, String> headers) {
        // 使用try-with-resources自动关闭HttpClient
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(url);
            setHeaders(httpGet, headers);

            // 使用ResponseHandler自动管理响应资源
            return httpClient.execute(httpGet, HttpClientTool::buildHttpResponse);
        } catch (IOException e) {
            log.error("远程调用http接口[{}]异常：", url, e);
            throw new RuntimeException(e);
        }
    }

    /**
     * description: 发送http post请求（form表单键值对）
     * @author 朱正磊
     * @date 2025-09-02 15:38:21
     */
    public static HttpResponse httpPostForm(String url, Map<String, String> params, Map<String, String> headers) {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(url);
            setHeaders(httpPost, headers);

            // 构造表单参数
            List<NameValuePair> paramList = new ArrayList<>();
            if (EmptyUtil.isNotEmpty(params)) {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    paramList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
            }
            httpPost.setEntity(new UrlEncodedFormEntity(paramList, StandardCharsets.UTF_8));

            // 使用ResponseHandler处理响应
            return httpClient.execute(httpPost, HttpClientTool::buildHttpResponse);
        } catch (IOException e) {
            log.error("远程调用http接口[{}]异常：", url, e);
            throw new RuntimeException(e);
        }
    }

    /**
     * description: 发送http post请求（json字符串）
     * @author 朱正磊
     * @date 2025-09-02 15:38:32
     */
    public static HttpResponse httpPostRaw(String url, String stringJson, Map<String, String> headers) {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(url);
            // 默认设置JSON类型头
            httpPost.setHeader("Content-type", "application/json");
            setHeaders(httpPost, headers);

            // 构造JSON实体
            StringEntity stringEntity = new StringEntity(stringJson, ContentType.APPLICATION_JSON);
            httpPost.setEntity(stringEntity);

            // 使用ResponseHandler处理响应
            return httpClient.execute(httpPost, HttpClientTool::buildHttpResponse);
        } catch (IOException e) {
            log.error("远程调用http接口[{}]异常：", url, e);
            throw new RuntimeException(e);
        }
    }

    /**
     * description: 发送http put请求（json字符串）
     * @author 朱正磊
     * @date 2025-09-02 15:38:43
     */
    public static HttpResponse httpPutRaw(String url, String stringJson, Map<String, String> headers) {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPut httpPut = new HttpPut(url);
            // 默认设置JSON类型头
            httpPut.setHeader("Content-type", "application/json");
            setHeaders(httpPut, headers);

            // 构造JSON实体
            StringEntity stringEntity = new StringEntity(stringJson, ContentType.APPLICATION_JSON);
            httpPut.setEntity(stringEntity);

            // 使用ResponseHandler处理响应
            return httpClient.execute(httpPut, HttpClientTool::buildHttpResponse);
        } catch (IOException e) {
            log.error("远程调用http接口[{}]异常：", url, e);
            throw new RuntimeException(e);
        }
    }

    /**
     * description: 发送http delete请求
     * @author 朱正磊
     * @date 2025-09-02 15:38:53
     */
    public static HttpResponse httpDelete(String url, Map<String, String> headers) {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpDelete httpDelete = new HttpDelete(url);
            setHeaders(httpDelete, headers);

            // 使用ResponseHandler处理响应
            return httpClient.execute(httpDelete, HttpClientTool::buildHttpResponse);
        } catch (IOException e) {
            log.error("远程调用http接口[{}]异常：", url, e);
            throw new RuntimeException(e);
        }
    }

    /**
     * description: 发送http post请求（文件上传）
     * @author 朱正磊
     * @date 2025-09-02 15:39:03
     */
    public static HttpResponse httpPostFormMultipart(String url,
                                                     Map<String, String> params, List<File> files, Map<String, String> headers) {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(url);
            setHeaders(httpPost, headers);

            // 构造多部分实体
            MultipartEntityBuilder mEntityBuilder = MultipartEntityBuilder.create();
            mEntityBuilder.setMode(HttpMultipartMode.EXTENDED);
            mEntityBuilder.setCharset(StandardCharsets.UTF_8);

            // 添加普通参数
            ContentType contentType = ContentType.create("text/plain", StandardCharsets.UTF_8);
            if (EmptyUtil.isNotEmpty(params)) {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    mEntityBuilder.addTextBody(entry.getKey(), entry.getValue(), contentType);
                }
            }

            // 添加文件
            if (EmptyUtil.isNotEmpty(files)) {
                for (File file : files) {
                    mEntityBuilder.addBinaryBody("file", file);
                }
            }

            httpPost.setEntity(mEntityBuilder.build());

            // 使用ResponseHandler处理响应
            return httpClient.execute(httpPost, HttpClientTool::buildHttpResponse);
        } catch (IOException e) {
            log.error("远程调用http接口[{}]异常：", url, e);
            throw new RuntimeException(e);
        }
    }

    // ------------------------------ 工具方法 ------------------------------

    /**
     * description: 统一设置请求头
     * @author 朱正磊
     * @date 2025-09-02 15:39:15
     */
    private static void setHeaders(HttpUriRequestBase request, Map<String, String> headers) {
        if (EmptyUtil.isNotEmpty(headers)) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                request.setHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * description: 统一构建自定义响应对象
     * @author 朱正磊
     * @date 2025-09-02 15:39:25
     */
    private static HttpResponse buildHttpResponse(ClassicHttpResponse httpResponse) {
        try {
            HttpResponse response = new HttpResponse();
            HttpEntity entity = httpResponse.getEntity();
            if (EmptyUtil.isNotEmpty(entity)) {
                String content = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                EntityUtils.consume(entity);
                response.setBody(content);
            }
            response.setHeaders(httpResponse.getHeaders());
            response.setReasonPhrase(httpResponse.getReasonPhrase());
            response.setStatusCode(httpResponse.getCode());
            return response;
        } catch (IOException | ParseException e) {
            throw new RuntimeException(e);
        }
    }

}
